﻿using System;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using Dapper;
using PDFDesign.Dapper;
using PDFDesign.Repository.Session;

namespace PDFDesign.Repository
{
    /// <summary>
    /// Repository基类
    /// </summary>
    /// <typeparam name="T"></typeparam>
    public class BaseRepository<T> : IRepository<T> where T : class
    {
        #region >>>>统计
        /// <summary>
        /// 根据条件查询记录总数
        /// </summary>
        /// <param name="conn"></param>
        /// <param name="predicate"></param>
        /// <returns></returns>
        public int Count(IDbConnection conn, IPredicate predicate)
        {
            return conn.Count<T>(predicate);
        }

        /// <summary>
        /// 根据SQL查询记录总数
        /// </summary>
        /// <param name="conn"></param>
        /// <param name="sql"></param>
        /// <returns></returns>
        public int Count(IDbConnection conn, string sql)
        {
            var cmd = conn.CreateCommand();
            try
            {
                cmd.CommandText = sql;
                cmd.CommandType = CommandType.Text;
                int count = (int)(ExecuteScalar(conn, cmd) ?? 0);
                return count;
            }
            catch
            {
                throw;
            }
            finally
            {
                if (cmd != null)
                    cmd.Dispose();
            }
        }

        /// <summary>
        /// 根据带参数SQL查询记录总数
        /// </summary>
        /// <param name="sql"></param>
        /// <param name="parameters"></param>
        /// <returns></returns>
        public int Count(string sql, object parameters = null)
        {
            using (var conn = SessionFactory.CreateConnection())
            {
                return conn.Query<int>(sql, parameters).Single();
            }
        }
        #endregion

        #region >>>>删除
        /// <summary>
        /// 根据主键删除记录
        /// </summary>
        /// <param name="primaryId"></param>
        /// <returns></returns>
        public bool Delete(dynamic primaryId)
        {
            var session = SessionFactory.CreateSession();
            session.BeginTrans();
            try
            {
                var isOk = Delete(session.Connection, primaryId, session.Transaction);
                session.Commit();
                return isOk;
            }
            catch (Exception)
            {
                session.Rollback();
                throw;
            }
            finally
            {
                session.Dispose();
            }
        }

        /// <summary>
        /// 根据主键删除记录
        /// </summary>
        /// <param name="conn"></param>
        /// <param name="primaryId"></param>
        /// <param name="transaction"></param>
        /// <returns></returns>
        public bool Delete(IDbConnection conn, dynamic primaryId, IDbTransaction transaction = null)
        {
            return conn.Delete(GetById(primaryId) as T, transaction);
        }

        /// <summary>
        /// 根据主键删除记录
        /// </summary>
        /// <param name="conn"></param>
        /// <param name="predicate"></param>
        /// <param name="transaction"></param>
        /// <returns></returns>
        public bool Delete(IDbConnection conn, IPredicate predicate, IDbTransaction transaction = null)
        {
            return conn.Delete<T>(predicate, transaction);
        }

        /// <summary>
        /// 根据字段列表批量删除
        /// </summary>
        /// <param name="conn"></param>
        /// <param name="name"></param>
        /// <param name="ids"></param>
        /// <returns></returns>
        public int DeleteBatch(IDbConnection conn, string name, IEnumerable<dynamic> ids)
        {
            return SqlMapper.Execute(conn,
                $"DELETE FROM dbo.{GetTableName()} WHERE {name} in (@values)",
                new { values = string.Join(",", ids.ToArray()) });
        }
        #endregion

        #region>>>>释放
        /// <summary>
        /// 释放
        /// </summary>
        public void Dispose()
        {

        }
        #endregion

        #region>>>>查询
        /// <summary>
        /// 根据字段列名称获取实体
        /// </summary>
        /// <param name="colName"></param>
        /// <param name="value"></param>
        /// <returns></returns>
        public IList<T> GetByName(string colName, string value)
        {
            var tblName = GetTableName();
            var sql = string.Format("SELECT * FROM {0} WHERE {1}=@colValue", tblName, colName);
            try
            {
                using (var conn = SessionFactory.CreateConnection())
                {
                    return SqlMapper.Query<T>(conn, sql, new { colValue = value }).ToList();
                }
            }
            catch
            {
                throw;
            }
        }

        /// <summary>
        /// 获取所有记录
        /// </summary>
        /// <returns></returns>
        public IEnumerable<T> GetAll()
        {
            var conn = SessionFactory.CreateConnection();
            try
            {
                return conn.GetList<T>();
            }
            catch
            {
                throw;
            }
            finally
            {
                conn.Close();
            }
        }

        /// <summary>
        /// 根据主键ID获取记录
        /// </summary>
        /// <param name="primaryId"></param>
        /// <returns></returns>
        public T GetById(dynamic primaryId)
        {
            var conn = SessionFactory.CreateConnection();
            try
            {
                return conn.Get<T>(primaryId as object);
            }
            catch
            {
                throw;
            }
            finally
            {
                conn.Close();
            }
        }

        /// <summary>
        /// 根据主键ID获取记录
        /// </summary>
        /// <param name="conn"></param>
        /// <param name="primaryId"></param>
        /// <param name="trans"></param>
        /// <returns></returns>
        public T GetById(IDbConnection conn, dynamic primaryId, IDbTransaction trans)
        {
            return conn.Get<T>(primaryId as object, trans);
        }

        /// <summary>
        /// 根据主键名获取记录
        /// </summary>
        /// <param name="ids"></param>
        /// <param name="name">主键名</param>
        /// <returns></returns>
        public IEnumerable<T> GetByIds(IList<dynamic> ids, string name)
        {
            var conn = SessionFactory.CreateConnection();
            try
            {
                return SqlMapper.Query<T>(conn,
                    $"SELECT * FROM dbo.{GetTableName()} WHERE {name} in (@ids)",
                    new { ids = string.Join(",", ids.ToArray()) });
            }
            catch
            {
                throw;
            }
            finally
            {
                conn.Close();
            }
        }

        /// <summary>
        /// 根据字段列名称获取实体
        /// </summary>
        /// <param name="colName"></param>
        /// <param name="value"></param>
        /// <returns></returns>
        public T GetDefaultByName(string colName, string value)
        {
            var dataList = GetByName(colName, value).ToList();
            return dataList.Count() > 0 ? dataList.FirstOrDefault() : null;
        }

        /// <summary>
        /// 查询匹配的一条数据
        /// </summary>
        /// <param name="sql"></param>
        /// <param name="param"></param>
        /// <param name="buffered"></param>
        /// <returns></returns>
        public T GetFirst(string sql, dynamic param = null, bool buffered = true)
        {
            using (IDbConnection conn = SessionFactory.CreateConnection())
            {
                T entity = null;
                var list = SqlMapper.Query<T>(conn, sql, param as object, null, buffered).ToList();
                if (list != null && list.Count() > 0)
                {
                    entity = list[0];
                }
                return entity;
            }
        }

        /// <summary>
        /// 查询匹配的一条数据
        /// </summary>
        /// <param name="conn"></param>
        /// <param name="sql"></param>
        /// <param name="param"></param>
        /// <param name="trans"></param>
        /// <param name="buffered"></param>
        /// <returns></returns>
        public T GetFirst(IDbConnection conn, string sql, dynamic param = null, IDbTransaction trans = null, bool buffered = true)
        {
            T entity = null;
            var list = SqlMapper.Query<T>(conn, sql, param as object, trans, buffered).ToList();
            if (list != null && list.Count() > 0)
            {
                entity = list[0];
            }
            return entity;
        }

        /// <summary>
        /// 查询列表数据
        /// </summary>
        /// <param name="conn"></param>
        /// <param name="predicate"></param>
        /// <param name="sort"></param>
        /// <param name="buffered"></param>
        /// <returns></returns>
        public IEnumerable<T> GetList(IDbConnection conn, IPredicate predicate = null, IList<ISort> sort = null, bool buffered = false)
        {
            return conn.GetList<T>(predicate, sort, null, null, buffered);
        }

        /// <summary>
        /// 分页查询
        /// </summary>
        /// <param name="conn"></param>
        /// <param name="pageIndex"></param>
        /// <param name="pageSize"></param>
        /// <param name="predictate"></param>
        /// <param name="sort"></param>
        /// <param name="buffered"></param>
        /// <returns></returns>
        public IEnumerable<T> GetPaged(IDbConnection conn, int pageIndex, int pageSize, object predictate, IList<ISort> sort = null, bool buffered = false)
        {
            return conn.GetPage<T>(predictate, sort, pageIndex, pageSize, null, null, buffered);
        }
        /// <summary>
        /// 根据条件筛选出数据集合
        /// </summary>
        /// <param name="sql"></param>
        /// <param name="param"></param>
        /// <param name="buffered"></param>
        /// <returns></returns>
        public IEnumerable<T> Query(string sql, dynamic param = null, bool buffered = true)
        {
            using (var conn = SessionFactory.CreateConnection())
            {
                return SqlMapper.Query<T>(conn, sql, param as object, null, buffered);
            }
        }

        /// <summary>
        /// 根据条件筛选出数据集合
        /// </summary>
        /// <param name="conn"></param>
        /// <param name="sql"></param>
        /// <param name="param"></param>
        /// <param name="trans"></param>
        /// <param name="buffered"></param>
        /// <returns></returns>
        public IEnumerable<T> Query(IDbConnection conn, string sql, dynamic param = null, IDbTransaction trans = null, bool buffered = true)
        {
            return SqlMapper.Query<T>(conn, sql, param as object, trans, buffered);
        }
        #endregion

        #region>>>>插入
        /// <summary>
        /// 插入一条记录
        /// </summary>
        /// <param name="entity"></param>
        /// <returns></returns>
        public dynamic Insert(T entity)
        {
            dynamic newId = null;
            var session = SessionFactory.CreateSession();
            session.BeginTrans();
            try
            {
                newId = Insert(session.Connection, entity, session.Transaction);
                session.Commit();
            }
            catch (Exception)
            {
                session.Rollback();
                throw;
            }
            finally
            {
                session.Dispose();
            }
            return newId;
        }

        /// <summary>
        /// 插入一条记录
        /// </summary>
        /// <param name="conn"></param>
        /// <param name="entity"></param>
        /// <param name="transaction"></param>
        /// <returns></returns>
        public dynamic Insert(IDbConnection conn, T entity, IDbTransaction transaction = null)
        {
            return conn.Insert(entity, transaction);
        }
        #endregion

        #region >>>>更新
        /// <summary>
        /// 批量更新记录
        /// </summary>
        /// <param name="conn"></param>
        /// <param name="entityList"></param>
        /// <param name="transaction"></param>
        /// <returns></returns>
        public bool UpdateBatch(IDbConnection conn, IEnumerable<T> entityList, IDbTransaction transaction = null)
        {
            foreach (var item in entityList)
            {
                Update(conn, item, transaction);
            }
            return true;
        }

        /// <summary>
        /// 更新一条记录
        /// </summary>
        /// <param name="entity"></param>
        /// <returns></returns>
        public bool Update(T entity)
        {
            var session = SessionFactory.CreateSession();
            session.BeginTrans();
            try
            {
                var isOk = Update(session.Connection, entity, session.Transaction);
                session.Commit();

                return isOk;
            }
            catch (Exception)
            {
                session.Rollback();
                throw;
            }
            finally
            {
                session.Dispose();
            }
        }

        /// <summary>
        /// 更新一条记录
        /// </summary>
        /// <param name="conn"></param>
        /// <param name="entity"></param>
        /// <param name="transaction"></param>
        /// <returns></returns>
        public bool Update(IDbConnection conn, T entity, IDbTransaction transaction = null)
        {
            return conn.Update(entity, transaction);
        }
        #endregion

        #region >>>>SQL
        /// <summary>
        /// 执行SQL
        /// </summary>
        /// <param name="sql"></param>
        /// <param name="param"></param>
        /// <returns></returns>
        public int Execute(string sql, dynamic param = null)
        {
            using (var conn = SessionFactory.CreateConnection())
            {
                return conn.Execute(sql, param as object);
            }
        }

        /// <summary>
        /// 执行SQL
        /// </summary>
        /// <param name="conn"></param>
        /// <param name="sql"></param>
        /// <param name="param"></param>
        /// <param name="transaction"></param>
        /// <returns></returns>
        public int Execute(IDbConnection conn, string sql, dynamic param = null, IDbTransaction transaction = null)
        {
            return conn.Execute(sql, param as object, transaction);
        }

        /// <summary>
        /// 执行SQL语句，并返回数值
        /// </summary>
        /// <param name="cmd"></param>
        /// <param name="conn"></param>
        /// <param name="transaction"></param>
        /// <returns></returns>
        public object ExecuteScalar(IDbConnection conn, IDbCommand cmd)
        {
            try
            {
                bool wasClosed = conn.State == ConnectionState.Closed;
                if (wasClosed) conn.Open();
                return cmd.ExecuteScalar();
            }
            catch (Exception)
            {
                throw;
            }
            finally
            {
                if (cmd != null)
                    cmd.Dispose();
            }
        }
        #endregion

        #region>>>>存储过程
        /// <summary>
        /// 执行存储过程方法
        /// </summary>
        /// <param name="procName"></param>
        /// <param name="param"></param>
        /// <returns></returns>
        public IList<T> ExecProcQuery(string procName, DynamicParameters param)
        {
            using (var conn = SessionFactory.CreateConnection())
            {
                IList<T> list = conn.Query<T>(procName, param, null, false, null, CommandType.StoredProcedure).ToList();
                return list;
            }
        }

        /// <summary>
        /// 执行存储过程方法
        /// </summary>
        /// <param name="conn"></param>
        /// <param name="procName"></param>
        /// <param name="param"></param>
        /// <returns></returns>
        public IList<T> ExecProcQuery(IDbConnection conn, string procName, DynamicParameters param)
        {
            return conn.Query<T>(procName, param, null, false, null, CommandType.StoredProcedure).ToList();
        }

        /// <summary>
        /// 执行command操作
        /// </summary>
        /// <param name="cmd"></param>
        /// <returns></returns>
        public int ExecuteCommand(IDbCommand cmd)
        {
            return cmd.ExecuteNonQuery();
        }

        /// <summary>
        /// 执行存储过程
        /// </summary>
        /// <param name="procName"></param>
        /// <param name="param"></param>
        /// <returns></returns>
        public int ExecuteProc(string procName, DynamicParameters param = null)
        {
            using (var conn = SessionFactory.CreateConnection())
            {
                return conn.Execute(procName, param, null, null, CommandType.StoredProcedure);
            }
        }

        /// <summary>
        /// 执行存储过程
        /// </summary>
        /// <param name="conn"></param>
        /// <param name="procName"></param>
        /// <param name="param"></param>
        /// <returns></returns>
        public int ExecuteProc(IDbConnection conn, string procName, DynamicParameters param = null)
        {
            return conn.Execute(procName, param, null, null, CommandType.StoredProcedure);
        }

        #endregion

        #region >>>>获取表名称
        /// <summary>
        /// 获取表名称
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <returns></returns>
        public string GetTableName()
        {
            var type = typeof(T);
            var attrs = Attribute.GetCustomAttributes(type);
            if (attrs.Length == 0)
            {
                var array = type.ToString().Split('.');
                if (array.Length == 0) return "";
                return array[array.Length - 1];
            }
            var tableName = (attrs[0] as dynamic).TableName;
            return tableName;
        }
        #endregion
    }
}
